import random
import types

from fastapi import APIRouter
from re_common.baselibrary.tools.all_requests.aiohttp_request import AioHttpRequest
from re_common.baselibrary.tools.all_requests.mrequest import MRequest
from re_common.baselibrary.utils.core.mlamada import bools_string
from re_common.baselibrary.utils.core.requests_core import MsgCode

from apps.allsubdb.cnkijournal.models import headers, DataArticleModel, DataRefModel, DataRefPageModel, DownIssueModel, \
    DownJournalId, DownYearModel, DataCitedPageModel, DownOutlineModel
from apps.core.global_model import MarksModel
from apps.core.m_route import ContextIncludedRoute
from apps.core.return_info import InputInfoModel, ReturnInfo

router = APIRouter(route_class=ContextIncludedRoute)


@router.post("/step1/journal_home")
async def journal_home(input: InputInfoModel[MarksModel]):
    """

    marks: lblPageCount
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    url = r'https://navi.cnki.net/knavi/Common/LeftNavi/Journal'
    marks = input.data.marks
    proxy = input.proxy
    form = {
        "productcode": "CJFD",
        "index": "1",
        "random": str(round(random.uniform(0, 1), 16)),
    }
    this_header = headers.copy()
    this_header["Accept"] = "text/plain, */*; q=0.01"
    rrq = AioHttpRequest()
    rrq.set_url(url).set_data(form) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy).set_header(this_header) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.POST)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step1/journal_list")
async def journal_list(input: InputInfoModel[DownJournalId]):
    """
    获取期刊列表的信息(在期刊导航页面 选择全部期刊 然后选择右边的列表展示图标)
    marks: lblPageCount
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    url = r'https://navi.cnki.net/KNavi/Common/Search/Journal'
    pageindex = input.data.page  # 第一页为1
    marks = input.data.marks
    proxy = input.proxy
    form = {
        'SearchStateJson': r'{"StateID":"","Platfrom":"","QueryTime":"","Account":"knavi","ClientToken":"","Language":"","CNode":{"PCode":"CJFD","SMode":"","OperateT":""},"QNode":{"SelectT":"","Select_Fields":"","S_DBCodes":"","QGroup":[],"OrderBy":"OTB|desc","GroupBy":"","Additon":""}}',
        'displaymode': '2',
        'pageindex': str(pageindex),
        'pagecount': '20',  # 21(网格模式为21)
        'index': '1',
        'random': '0.18096246145757267'
    }
    # 学科导航 如果不是class 就是全部期刊翻页就可以了
    # input.data.asscii 为 字母A到J对应学科导航的10个大分类
    if input.data.type == "class":
        SearchStateJson = r'{"StateID":"","Platfrom":"","QueryTime":"","Account":"knavi","ClientToken":"","Language":"","CNode":{"PCode":"CJFD","SMode":"","OperateT":""},"QNode":{"SelectT":"","Select_Fields":"","S_DBCodes":"","QGroup":[{"Key":"Navi","Logic":1,"Items":[],"ChildItems":[{"Key":"Journal","Logic":1,"Items":[{"Key":1,"Title":"","Logic":1,"Name":"168专题代码","Operate":"","Value":"%s?","ExtendType":0,"ExtendValue":"","Value2":""}],"ChildItems":[]}]}],"OrderBy":"OTA|DESC","GroupBy":"","Additon":""}}'
        form["SearchStateJson"] = SearchStateJson % input.data.subject
    form['random'] = str(round(random.uniform(0, 1), 16))
    this_header = headers.copy()
    rrq = AioHttpRequest()
    rrq.set_url(url).set_data(form) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy).set_header(this_header) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.POST)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step2/down_journal_info")
async def down(input: InputInfoModel[DownYearModel]):
    """
    下载单独的期刊信息
    marks: titbox
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    pykm = input.data.pykm
    marks = input.data.marks
    proxy = input.proxy
    this_header = headers.copy()
    url = r'https://navi.cnki.net/knavi/JournalDetail?pcode=CJFD&pykm=%s' % pykm
    rrq = AioHttpRequest()
    rrq.set_url(url).set_header(this_header) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.POST)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step5/down_year")
async def down_year(input: InputInfoModel[DownYearModel]):
    """
    下载年列表 可以解析出年和期的信息
    marks: YearIssueTree
    :param input: 
    :return: 
    """
    return_info = ReturnInfo()
    pykm = input.data.pykm
    marks = input.data.marks
    proxy = input.proxy
    this_header = headers.copy()
    this_header['Referer'] = 'https://navi.cnki.net/knavi/JournalDetail?pcode=CJFD&pykm=%s' % pykm
    url = r'https://navi.cnki.net/knavi/JournalDetail/GetJournalYearList?pcode=CJFD&pykm=%s&pIdx=0' % pykm
    rrq = AioHttpRequest()
    rrq.set_url(url).set_header(this_header) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.POST)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step5/down_getnfalloutline")
async def down_getnfalloutline(input: InputInfoModel[DownOutlineModel]):
    """
    下载网络首发
    marks: clearfix
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    pcode = input.data.pcode
    type = input.data.type
    pageIdx = input.data.pageIdx
    pykm = input.data.pykm
    marks = input.data.marks
    proxy = input.proxy
    url = r'https://navi.cnki.net/knavi/JournalDetail/GetnfAllOutline'
    this_header = headers.copy()
    form = {
        "pykm": pykm,
        "pcode": pcode,
        "pageIdx": pageIdx,
        "type": type,
    }
    rrq = AioHttpRequest()

    rrq.set_url(url).set_params(form) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy).set_header(this_header) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.POST)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step7/down_issue")
async def down_issue(input: InputInfoModel[DownIssueModel]):
    """
    下载期，下载的结果用于解析文章id
    marks 建议为 "articleCount"
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    pubyear = input.data.pubyear
    num = input.data.num
    pykm = input.data.pykm
    pageIdx = input.data.pageIdx
    marks = input.data.marks
    proxy = input.proxy
    # url = r'https://navi.cnki.net/knavi/JournalDetail/GetArticleList?year=%s&issue=%s&pykm=%s&pageIdx=%s&pcode=CJFD'
    # url = url % (pubyear, num, pykm,str(pageIdx))
    url = r'https://navi.cnki.net/knavi/JournalDetail/GetArticleList'
    form = {
        'year': pubyear,
        'issue': num,
        'pykm': pykm,
        'pageIdx': str(pageIdx),
        'pcode': 'CJFD'
    }
    this_header = headers.copy()
    this_header['Referer'] = 'https://navi.cnki.net/knavi/JournalDetail?pcode=CJFD&pykm={}'.format(pykm)
    this_header['sec-ch-ua'] = '"Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"'
    rrq = AioHttpRequest()

    rrq.set_url(url).set_params(form) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy).set_header(this_header) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.POST)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step8/down_article")
async def down_article(input: InputInfoModel[DataArticleModel]):
    """
    下载期刊的国内版元数据信息，为期刊信息服务
    marks 建议为 filename.lower(),'brief'

    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    this_header = headers.copy()
    knsUrl = r'https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&filename=%s' % filename
    rrq = AioHttpRequest()

    def article_middlerwares(self):
        """
        验证返回码
        :return:
        """
        if self.html.find('所查找的文献不存在') != -1:
            self.resp_dicts["code"] = MsgCode.NO_RESOURCE
            self.resp_dicts["msg"] = "所查找的文献不存在"
            return False, self.resp_dicts
        return True, self.resp_dicts

    rrq.article_middlerwares = types.MethodType(article_middlerwares, rrq)

    rrq.set_header(this_header).set_url(knsUrl) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.have_end_middlerwares, rrq.article_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step8/down_online")
async def down_article(input: InputInfoModel[DataArticleModel]):
    """
    下载期刊的国内版元数据信息，为期刊信息服务
    marks 建议为 filename.lower(),'brief'

    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    this_header = headers.copy()
    this_header["Host"] = "kns.cnki.net"
    this_header["Referer"] = "https://navi.cnki.net/"
    del this_header["Origin"]
    knsUrl = r'https://kns.cnki.net/kcms/detail/%s.html' % filename
    rrq = AioHttpRequest()

    def article_middlerwares(self):
        """
        验证返回码
        :return:
        """
        if self.html.find('所查找的文献不存在') != -1:
            self.resp_dicts["code"] = MsgCode.NO_RESOURCE
            self.resp_dicts["msg"] = "所查找的文献不存在"
            return False, self.resp_dicts
        return True, self.resp_dicts

    rrq.article_middlerwares = types.MethodType(article_middlerwares, rrq)

    rrq.set_header(this_header).set_url(knsUrl) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.have_end_middlerwares, rrq.article_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html}
    return return_info.todict()


@router.post("/step8/down_article_oversea")
async def down_article(input: InputInfoModel[DataArticleModel]):
    """
    下载期刊的元数据海外版信息，单独下载不依赖
    marks 建议为 filename.lower(),'container','wx-tit'

    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    this_header = headers.copy()

    oversea = r'https://oversea.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&filename=%s' % filename
    rrq = AioHttpRequest()

    def article_middlerwares(self):
        """
        验证返回码
        :return:
        """
        if self.html.find('所查找的文件不存在') != -1:
            self.resp_dicts["code"] = MsgCode.NO_RESOURCE
            self.resp_dicts["msg"] = "所查找的文件不存在"
            return False, self.resp_dicts
        return True, self.resp_dicts

    rrq.article_middlerwares = types.MethodType(article_middlerwares, rrq)

    rrq.set_header(this_header).set_url(oversea) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.have_end_middlerwares, rrq.article_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)

    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html, "url": oversea}
    return return_info.todict()


@router.post("/step9/down_ref")
async def down_ref(input: InputInfoModel[DataRefModel]):
    """
    20200923:
    下载引文 目前引文需要依赖题录下载的vl值;
    marks: 建议为 参考文献;
    year： 为年份，一般学校的 dbname=CJFDLAST+year 但api请求时uid 和year都是没有的，目前不要年依然可以成功;
    vl: vl为article请求后得到的，目前测试大概1小时左右有效;
    filename: 目前大小写无影响;
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    year = input.data.year
    vl = input.data.vl
    uid = input.data.uid
    this_header = headers.copy()
    del this_header["Origin"]
    this_header[
        'Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
    this_header[
        'Referer'] = 'https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&filename=%s&dbname=CJFDLAST%s&uid=%s' % (
        filename, year, uid)
    this_header['Host'] = 'kns.cnki.net'
    this_header['Sec-Fetch-Dest'] = 'iframe'
    url = r'https://kns.cnki.net/kcms/detail/frame/list.aspx?dbcode=CJFD&filename=%s&dbname=CJFDLAST%s&RefType=1&vl=%s' % (
        filename.lower(), year, vl)

    def article_middlerwares(self):
        """
        验证返回码
        :return:
        """
        if self.html.find('未找到相关数据') != -1:
            self.resp_dicts["code"] = MsgCode.NO_RESOURCE
            self.resp_dicts["msg"] = "所查找的文件不存在"
            return False, self.resp_dicts
        return True, self.resp_dicts

    rrq = AioHttpRequest()
    rrq.article_middlerwares = types.MethodType(article_middlerwares, rrq)
    rrq.set_header(this_header).set_url(url) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.have_end_middlerwares, rrq.article_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html, "url": url}
    return return_info.todict()


@router.post("/step9/down_ref_page")
async def down_ref(input: InputInfoModel[DataRefPageModel]):
    """
    20200923:
    下载引文(翻页，不是第一页，翻页请求与第一页请求有所不同) 目前引文需要依赖题录下载的vl值;
    marks: 建议为 参考文献;
    year： 为年份，一般学校的 dbname=CJFDLAST+year 但api请求时uid 和year都是没有的，目前不要年依然可以成功;
    vl: vl为article请求后得到的，目前测试大概1小时左右有效;
    filename: 目前大小写无影响;
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    year = input.data.year
    vl = input.data.vl
    uid = input.data.uid
    curdbcode = input.data.curdbcode
    page = input.data.page
    this_header = headers.copy()
    this_header[
        'Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
    this_header[
        'Referer'] = 'https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&filename=%s&dbname=CJFDLAST%s&uid=%s' % (
        filename, year, uid)
    this_header['Host'] = 'kns.cnki.net'
    this_header['Sec-Fetch-Dest'] = 'iframe'
    url = r'https://kns.cnki.net/kcms/detail/frame/list.aspx?dbcode=CJFD&filename=%s&dbname=CJFDLAST%s&RefType=1&vl=%s&CurDBCode=%s&page=%s' % (
        filename, year, vl, curdbcode, page)

    def article_middlerwares(self):
        """
        验证返回码
        :return:
        """
        if self.html.find('未找到相关数据') != -1:
            self.resp_dicts["code"] = MsgCode.NO_RESOURCE
            self.resp_dicts["msg"] = "所查找的文件不存在"
            return False, self.resp_dicts
        return True, self.resp_dicts

    rrq = AioHttpRequest()
    rrq.article_middlerwares = types.MethodType(article_middlerwares, rrq)
    rrq.set_header(this_header).set_url(url) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.have_end_middlerwares, rrq.article_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html, "url": url}
    return return_info.todict()


@router.post("/step10/down_cited_page")
async def down_cited(input: InputInfoModel[DataCitedPageModel]):
    """
    20201111:
    下载被引(翻页，不是第一页，翻页请求与第一页请求有所不同) 目前引文需要依赖题录下载的vl值;
    marks: 建议为 引证文献;
    year： 为年份，一般学校的 dbname=CJFDLAST+year 但api请求时uid 和year都是没有的，目前不要年依然可以成功;
    vl: vl为article请求后得到的，目前测试大概1小时左右有效;
    filename: 目前大小写无影响;
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    dbname = input.data.dbname
    vl = input.data.vl
    uid = input.data.uid
    curdbcode = input.data.curdbcode
    page = input.data.page
    this_header = headers.copy()
    this_header[
        'Referer'] = 'https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&filename=%s&dbname=%s&uid=%s' % (
        filename, dbname, uid)
    this_header['Sec-Fetch-Dest'] = 'iframe'
    url = r'https://kns.cnki.net/kcms/detail/frame/list.aspx?dbcode=CJFD&filename=%s&dbname=%s&RefType=3&vl=%s&CurDBCode=%s&page=%s' % (
        filename, dbname, vl, curdbcode, page)

    def article_middlerwares(self):
        """
        验证返回码
        :return:
        """
        if self.html.find('未找到相关数据') != -1:
            self.resp_dicts["code"] = MsgCode.NO_RESOURCE
            self.resp_dicts["msg"] = "所查找的文件不存在"
            return False, self.resp_dicts
        return True, self.resp_dicts

    rrq = AioHttpRequest()
    rrq.article_middlerwares = types.MethodType(article_middlerwares, rrq)
    rrq.set_header(this_header).set_url(url) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.have_end_middlerwares, rrq.article_middlerwares, rrq.marks_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"html": rrq.html, "url": url}
    return return_info.todict()


@router.post("/step11/down_refcount")
async def down_refcount(input: InputInfoModel[DataArticleModel]):
    """
    下载引文数量信息，目前下载不依赖题录下载，但已经发现参数vl，不确认后面是否需要依赖
    marks 建议为 'REFERENCE'

    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    proxy = input.proxy
    filename = input.data.filename
    this_header = headers.copy()
    this_header['Referer'] = r'https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&filename=%s' % filename

    url = r'https://kns.cnki.net/kcms/detail/block/refcount.aspx?dbcode=CJFD&filename=%s&vl=' % filename
    rrq = AioHttpRequest()

    def on_request_end(self):
        if self.html:
            self.html = self.html.replace("'", '"')  # 单引号替换为双引号

    rrq.on_request_end = types.MethodType(on_request_end, rrq)

    rrq.set_header(this_header).set_url(url) \
        .set_timeout(30).set_marks(marks) \
        .set_proxy(proxy) \
        .set_middler_list(
        [rrq.status_code_middlerwares, rrq.marks_middlerwares, rrq.is_json_middlerwares])
    bools, dicts = await rrq.run(MRequest.GET)
    return_info.status = bools_string(bools)
    return_info.msg_code = dicts["code"]
    return_info.msg = dicts["msg"]
    return_info.data = {"jsons": rrq.html, "url": url}
    return return_info.todict()
